function hook_api(func_code) {
    if (!func_code) return;
    var tar = document.createElement('script');
    var func_tostring = func_code.toString();
    tar.innerHTML =
        `
        (${window.eval(func_tostring)})()
    `;
    document.documentElement.insertBefore(tar, document.head)
    // document.documentElement.prepend(tar);
};
// 内置三大基本函数 toString保护函数 + 代理函数 + AJAX
hook_api(
    () => {
        window.mengqi = {};
        mengqi.proxy = function proxy(obj) {
            return new Proxy(obj, {
                set(obj, prop, value) {
                    var objName = obj.name || obj.toString().replace(/\[|\]/g, '').split(' ')[1];
                    var value_ = value.toString();
                    console.log('set：' + objName + '[' + prop + ']' + '===>' + value_);
                    debugger;
                    return Reflect.set.apply(this, arguments);
                },
                get(obj, prop) {
                    var objName = obj.name || obj.toString().replace(/\[|\]/g, '').split(' ')[1];
                    var value = obj[prop];
                    if (!value) {
                        var value_ = value;
                    } else { var value_ = value.toString() }
                    console.log('get：' + objName + '[' + prop + ']' + '===>' + value_);
                    debugger;
                    return value;
                }
            })
        }
    }
);
hook_api(
    () => {
        const $toString = Function.toString;
        const Symbol_toString = Symbol('()_' + Math.random());
        const mytoString = function () { return typeof this == 'function' && this[Symbol_toString] || $toString.call(this); }
        const set_native = function (obj, prop, value) {
            return Object.defineProperty(obj, prop, {
                enumerable: false,
                configurable: true,
                writable: true,
                value: value
            });
        };
        delete Function.prototype.toString;
        set_native(Function.prototype, 'toString', mytoString);
        set_native(Function.prototype.toString, Symbol_toString, `function toString() { [native code] }`);
        mengqi.protect = function (obj) {
            return set_native(obj, Symbol_toString, `function ${obj.name}() { [native code] }`);
        };
    }
);
hook_api(
    ()=>{
        mengqi.xml=function(url){
            var xml = new XMLHttpRequest;
            xml.open('post',url);
            xml.onreadystatechange=(e)=>{
                if((e.status==200)&&(e.readyState==4)){
                    return true;
                }
            };
            
        }
    }
);
// 代理2
hook_api(
    ()=>{
    function proxy_(){
        var prop = this.prop;
        Object.defineProperty(this,'prop',{
            get:function(){
                debugger;
                return prop;
            },
            set:function(value_){
                debugger;
                prop = value_;
            }
        });
    
    };
    proxy__ = proxy_;
    window.object_proxy= function(obj,prop,objName){
        objName = objName || obj.name || obj.toString().replace(/\[|\]/g, '').split(' ')[1];
        var rg = /prop/g;
        var str = proxy__.toString().replace(rg,prop);
        this.eval(str.replace(/this/g,objName));
        obj = new proxy_();
    };}  
)
// RPC调用
hook_api(
    ()=>{
        function SekiroClient(wsURL) {
            this.wsURL = wsURL;
            this.handlers = {};
            this.socket = {};
            // check
            if (!wsURL) {
                throw new Error('wsURL can not be empty!!')
            }
            this.webSocketFactory = this.resolveWebSocketFactory();
            this.connect()
        }
    
        SekiroClient.prototype.resolveWebSocketFactory = function() {
            if (typeof window === 'object') {
                var theWebSocket = window.WebSocket ? window.WebSocket : window.MozWebSocket;
                return function(wsURL) {
    
                    function WindowWebSocketWrapper(wsURL) {
                        this.mSocket = new theWebSocket(wsURL);
                    }
    
                    WindowWebSocketWrapper.prototype.close = function() {
                        this.mSocket.close();
                    }
                    ;
    
                    WindowWebSocketWrapper.prototype.onmessage = function(onMessageFunction) {
                        this.mSocket.onmessage = onMessageFunction;
                    }
                    ;
    
                    WindowWebSocketWrapper.prototype.onopen = function(onOpenFunction) {
                        this.mSocket.onopen = onOpenFunction;
                    }
                    ;
                    WindowWebSocketWrapper.prototype.onclose = function(onCloseFunction) {
                        this.mSocket.onclose = onCloseFunction;
                    }
                    ;
    
                    WindowWebSocketWrapper.prototype.send = function(message) {
                        this.mSocket.send(message);
                    }
                    ;
    
                    return new WindowWebSocketWrapper(wsURL);
                }
            }
            if (typeof weex === 'object') {
                // this is weex env : https://weex.apache.org/zh/docs/modules/websockets.html
                try {
                    console.log("test webSocket for weex");
                    var ws = weex.requireModule('webSocket');
                    console.log("find webSocket for weex:" + ws);
                    return function(wsURL) {
                        try {
                            ws.close();
                        } catch (e) {}
                        ws.WebSocket(wsURL, '');
                        return ws;
                    }
                } catch (e) {
                    console.log(e);
                    //ignore
                }
            }
            //TODO support ReactNative
            if (typeof WebSocket === 'object') {
                return function(wsURL) {
                    return new theWebSocket(wsURL);
                }
            }
            // weex 和 PC环境的websocket API不完全一致，所以做了抽象兼容
            throw new Error("the js environment do not support websocket");
        }
        ;
    
        SekiroClient.prototype.connect = function() {
            console.log('sekiro: begin of connect to wsURL: ' + this.wsURL);
            var _this = this;
            // 不check close，让
            // if (this.socket && this.socket.readyState === 1) {
            //     this.socket.close();
            // }
            try {
                this.socket = this.webSocketFactory(this.wsURL);
            } catch (e) {
                console.log("sekiro: create connection failed,reconnect after 2s");
                setTimeout(function() {
                    _this.connect()
                }, 2000)
            }
    
            this.socket.onmessage(function(event) {
                _this.handleSekiroRequest(event.data)
            });
    
            this.socket.onopen(function(event) {
                console.log('sekiro: open a sekiro client connection')
            });
    
            this.socket.onclose(function(event) {
                console.log('sekiro: disconnected ,reconnection after 2s');
                setTimeout(function() {
                    _this.connect()
                }, 2000)
            });
        }
        ;
    
        SekiroClient.prototype.handleSekiroRequest = function(requestJson) {
            console.log("receive sekiro request: " + requestJson);
            var request = JSON.parse(requestJson);
            var seq = request['__sekiro_seq__'];
    
            if (!request['action']) {
                this.sendFailed(seq, 'need request param {action}');
                return
            }
            var action = request['action'];
            if (!this.handlers[action]) {
                this.sendFailed(seq, 'no action handler: ' + action + ' defined');
                return
            }
    
            var theHandler = this.handlers[action];
            var _this = this;
            try {
                theHandler(request, function(response) {
                    try {
                        _this.sendSuccess(seq, response)
                    } catch (e) {
                        _this.sendFailed(seq, "e:" + e);
                    }
                }, function(errorMessage) {
                    _this.sendFailed(seq, errorMessage)
                })
            } catch (e) {
                console.log("error: " + e);
                _this.sendFailed(seq, ":" + e);
            }
        }
        ;
    
        SekiroClient.prototype.sendSuccess = function(seq, response) {
            var responseJson;
            if (typeof response == 'string') {
                try {
                    responseJson = JSON.parse(response);
                } catch (e) {
                    responseJson = {};
                    responseJson['data'] = response;
                }
            } else if (typeof response == 'object') {
                responseJson = response;
            } else {
                responseJson = {};
                responseJson['data'] = response;
            }
    
            if (Array.isArray(responseJson)) {
                responseJson = {
                    data: responseJson,
                    code: 0
                }
            }
    
            if (responseJson['code']) {
                responseJson['code'] = 0;
            } else if (responseJson['status']) {
                responseJson['status'] = 0;
            } else {
                responseJson['status'] = 0;
            }
            responseJson['__sekiro_seq__'] = seq;
            var responseText = JSON.stringify(responseJson);
            console.log("response :" + responseText);
            this.socket.send(responseText);
        }
        ;
    
        SekiroClient.prototype.sendFailed = function(seq, errorMessage) {
            if (typeof errorMessage != 'string') {
                errorMessage = JSON.stringify(errorMessage);
            }
            var responseJson = {};
            responseJson['message'] = errorMessage;
            responseJson['status'] = -1;
            responseJson['__sekiro_seq__'] = seq;
            var responseText = JSON.stringify(responseJson);
            console.log("sekiro: response :" + responseText);
            this.socket.send(responseText)
        }
        ;
    
        SekiroClient.prototype.registerAction = function(action, handler) {
            if (typeof action !== 'string') {
                throw new Error("an action must be string");
            }
            if (typeof handler !== 'function') {
                throw new Error("a handler must be function");
            }
            console.log("sekiro: register action: " + action);
            this.handlers[action] = handler;
            return this;
        }
        ;
    
        function guid() {
            function S4() {
                return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
            }
    
            return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
        }
    
        window.ws = function(){
            var func = arguments[1];
            var client = new SekiroClient("ws://127.0.0.1:5620/business-demo/register?group=rpc-test&clientId=" + guid());
    
            client.registerAction(arguments[0], function(request, resolve, reject) {
                resolve(func.apply(this,Object.values(request).slice(3)));
            });
            console.log('The API：'+ `http://127.0.0.1:5620/business-demo/invoke?group=rpc-test&action=${arguments[0]}&url=any`)
        }
    }
)


// test_localstorage
chrome.storage.sync.get(['code'], (e) => {
    if (!e.code) return;
    if (Object.values(e.code).every((e) => { return (e == null) })) return;
    e.code.forEach(element => {
        if (element && element.state) hook_api(element.code);
    });
})
chrome.runtime.onMessage.addListener(
    function (request, sender, sendResponse) {
        console.log('收到消息')
        if (request.action == "other_hook") {
            var code = request.code;
            console.log(`开始设置${code}`);
            localStorage['code'] = code;
            hook_api(code);
            sendResponse({ state: 'other_hook is set done!' });
            location.reload();
        };
        if (request.action === 'get_xpath') {
            if (!document.getElementById('xp_table')) {
                document.body.prepend(xp_table);
            };
            display_xpath_option(sendResponse);
        }
    }
);
(() => {
    window.xp_table = document.createElement('div');
    xp_table.id = 'xp_table';
    xp_table.style.display = 'none';
    var add_table = document.createElement('a');
    add_table.textContent = 'ADD TABLE'
    xp_table.append(add_table);
    add_table.addEventListener('click', () => {
        create_xp_table();
    });
    display_xpath_option = (sendResponse) => {
        if (xp_table.style.display) {
            xp_table.style.display = '';
            sendResponse({ state: 'xpath_table is displaying' });
        } else {
            xp_table.style.display = 'none';
            sendResponse({ state: 'xpath_table is slepping' });
        };
    };
})();

function get_xpath(e) {
    var xpath_value = document.getElementById('waiting');
    if (e.shiftKey && xpath_value) {
        var getElementIndex = function (el) {
            var index = 1;  // XPath is one-indexed
            var sib;
            for (sib = el.previousSibling; sib; sib = sib.previousSibling) {
                if (sib.nodeType === Node.ELEMENT_NODE && elementsShareFamily(el, sib)) {
                    index++;
                }
            }
            if (index > 1) {
                return index;
            }
            for (sib = el.nextSibling; sib; sib = sib.nextSibling) {
                if (sib.nodeType === Node.ELEMENT_NODE && elementsShareFamily(el, sib)) {
                    return 1;
                }
            }
            return 0;
        };

        var makeQueryForElement = function (el) {
            var query = '';
            for (; el && el.nodeType === Node.ELEMENT_NODE; el = el.parentNode) {
                var component = el.tagName.toLowerCase();
                var index = getElementIndex(el);
                if (el.id) {
                    component += '[@id=\'' + el.id + '\']';
                } else if (el.className) {
                    component += '[@class=\'' + el.className + '\']';
                }
                if (index >= 1) {
                    component += '[' + index + ']';
                }
                // If the last tag is an img, the user probably wants img/@src.
                if (query === '' && el.tagName.toLowerCase() === 'img') {
                    component += '/@src';
                }
                query = '/' + component + query;
            }
            return query;
        };
        var elementsShareFamily = function (primaryEl, siblingEl) {
            var p = primaryEl, s = siblingEl;
            return (p.tagName === s.tagName &&
                (!p.className || p.className === s.className) &&
                (!p.id || p.id === s.id));
        };
        xpath_value.textContent = makeQueryForElement(e.target);
        document.getElementById('display').textContent = e.target.textContent;
    };
};
function remove_addlistener(e) {
    if (e.keyCode == 16) {
        document.removeEventListener('mousemove', get_xpath);
        document.removeEventListener('mouseup', remove_addlistener)
    }
};
function create_xp_table() {
    window.create_xp_table = create_xp_table;
    var table = document.createElement('table');
    xp_table.prepend(table);
    var table_0 = document.createElement('caption')
    table.append(table_0)
    table_0.textContent = '请输入表名！';
    table_0.addEventListener('click', () => {
        var value = prompt('表名');
        table_0.textContent = value;
    });
    var table_is_display = document.createElement('a');
    table_is_display.textContent = '隐藏';
    table.append(table_is_display);
    var thead = document.createElement('thead');
    table.append(thead);
    thead.innerHTML = `
            <tr>
                <td>name</td><td>xpath</td><td>display</td>
            </tr>
            `;
    var t_body = document.createElement('tbody');
    table.append(t_body);
    t_body.id = 'display_tbody';
    document.getElementById('display_tbody').id = 'nodisplay_tbody';
    document.getElementById('nodisplay_tbody').style.display = 'none';
    t_body.id = 'display_tbody';
    document.getElementById('display_tbody').style.display = '';
    var column_add = document.createElement('a');
    column_add.textContent = 'ADD COLUMN';
    t_body.append(column_add);
    column_add.addEventListener('click', () => {
        var tr = document.createElement('tr');
        t_body.append(tr);
        tr.innerHTML = `
                <td>please write the name of the column</td>
                <td id="waiting">please caperture any you want to display</td>
                <td>none</td>
                `;
        tr.children[2].id = 'display';
        document.getElementById('display').id = 'no_display';
        tr.children[2].id = 'display';
        var column = tr.children[0];
        column.addEventListener('click', () => {
            var name = prompt('name');
            column.textContent = name;
        });
        var caperture = tr.children[1];
        document.getElementById('waiting').id = 'slepping';
        caperture.id = 'waiting';
        caperture.addEventListener('click', () => {
            var con = confirm('修改当前xpath路径');
            if (con) {
                document.getElementById('waiting').id = 'slepping';
                caperture.id = 'waiting';
                document.getElementById('display').id = 'no_display';
                caperture.parentElement.children[2].id = 'display';
            };
        });
        document.addEventListener('mouseup', remove_addlistener, true)
        document.addEventListener('mousemove', get_xpath);
    });
    table_is_display.addEventListener('click', (e) => {
        if (e.target.parentElement.children[3].id == 'display_tbody') {
            e.target.parentElement.children[3].id = 'nodisplay_tbody';
            e.target.parentElement.children[3].style.display = 'none';
        } else {
            document.getElementById('nodisplay_tbody').style.display = '';
            e.target.parentElement.children[3].id = 'display_tbody';
            e.target.parentElement.children[3].style.display = '';
        }
        if (table_is_display.textContent == '隐藏') {
            table_is_display.textContent = '显示';
        } else {
            table_is_display.textContent = '隐藏';
        }
    });
};
// options，back 无法发送消息给 content ====> 曲线救国
// 1.options创建hook项目 2.background注册代码 
// 3.popup获取以及启动options或者background的函数结果并将信息传入content